#include <sys_config.h>
#include <osal/osal.h>
#include <basic_types.h>
#include <Mediatypes.h>

#include <api/libc/printf.h>
#include <api/libc/alloc.h>
#include <api/libc/string.h>

#include <hld/hld_dev.h>
#include <hld/vbi/vbi.h>
#include <hld/vbi/vbi_dev.h>
#include <hld/dis/vpo.h>
#include <hal/hal_common.h>

#include "vbi_buffer.h"
#include "vbi_m3327.h"

//#include "../../../dis/m3327/tv_enc.h"

/*config par*/
struct vbi_config_par *g_vbi27_pconfig_par = NULL;
UINT8 *g_vbi27_ttx_by_osd = NULL;
//#ifdef ENABLE_ATSC_USER_DATA
UINT8 *g_vbi27_cc_by_osd = NULL;
//========================
UINT16 *g_vbi27_dtvcc_by_osd=NULL;
BOOL g_disable_process_cc=FALSE;
BOOL recv_PAC=FALSE;
UINT32 vbi_rating=0;
UINT32 pre_vbi_rating=0;
BOOL vbi_CC=FALSE;
//BOOL g_stop_cc=FALSE;
//UINT8 cc_field=0;
//#endif //vicky20101229 dbg
//========================

char vbi_m3327_name[HLD_MAX_NAME_SIZE] = "VBI_M3327_0";
struct vbi_m3327_private *g_vbi_priv;
#ifdef SEE_CPU
struct vbi_device * g_vbi_device;
extern void ttx_eng_update_page_cb(UINT16 Param1,UINT8 Param2);
#endif

/*variable & array for TTX decoder*/
t_TTXDecCBFunc pCBPageUpdate;
UINT8 g_packet_exist[8][25];
UINT8 * g_ttx_p26_nation = NULL;//(UINT8 *)((__MM_TTX_P26_NATION_BUF_ADDR & 0xfffffff) | 0x80000000);
//UINT8 *g_ttx_p26_data = NULL;//(UINT8 *)((__MM_TTX_P26_DATA_BUF_ADDR & 0xfffffff) | 0x80000000);

OSAL_ID vbidec_tsk_id;
OSAL_ID vbidec_flag_id;
struct VBIDataHdr *vbi_data_hdr = NULL;
static volatile UINT16 vbi_queue_wr;
static volatile UINT16 vbi_queue_rd;
static volatile UINT16 vbi_queue_cnt;

//static struct vbi_data_array_t vbi_data_array[VBI_QUEUE_DEPTH];
struct vbi_data_array_t *vbi_data_array = NULL;//change to dynamic alloc to aviod gp overflow
static BOOL enable_vbi = TRUE;//used to disable vbi data transfer in some cases, cloud 

static INLINE void vbi_queue_init()
{
	vbi_queue_wr = 0;
	vbi_queue_rd = 0;
	vbi_queue_cnt = 0;
}
static INLINE BOOL vbi_queue_is_empty()
{
	return (vbi_queue_cnt==0)?TRUE:FALSE;
}
static INLINE BOOL vbi_queue_is_full()
{
	return (vbi_queue_cnt==VBI_QUEUE_DEPTH)?TRUE:FALSE;
}
static INLINE UINT16 vbi_queue_wr_ptr()
{
	return vbi_queue_wr;
}
static INLINE UINT16 vbi_queue_rd_ptr()
{
	return vbi_queue_rd;
}
static INLINE void vbi_queue_put()
{
	//soc_printf("+");
	vbi_queue_wr = (vbi_queue_wr==VBI_QUEUE_DEPTH-1)?0:(vbi_queue_wr+1);
	vbi_queue_cnt ++;
}
static INLINE void vbi_queue_get()
{
	//soc_printf("-");
	vbi_queue_rd = (vbi_queue_rd==VBI_QUEUE_DEPTH-1)?0:(vbi_queue_rd+1);
	vbi_queue_cnt --;
}

void enable_vbi_transfer(BOOL enable)//cloud
{
    enable_vbi = enable;
}

//#define vbi_output_proc tve_write_ttx
//#define vbi_output_proc tve_sd_write_ttx

static void vbi_output_proc(UINT8 LineAddr, UINT8 Addr, UINT8 Data)
{
    struct tve_device *ptve_dev = dev_get_by_id(HLD_DEV_TYPE_TVE, g_vbi_priv->tve_dev_id);

    if (ptve_dev)
    {
        tvenc_write_ttx(ptve_dev, LineAddr, Addr, Data);
    }
    else
    {
        tve_write_ttx(LineAddr,Addr, Data);
     }
}
    
static UINT8 do_line_data(UINT8 * pData ,UINT32 Size, UINT32 * len)
{ //FieldPolar 1: TOP (7-22), 0 : BOT (320-335)
	UINT8 FieldPolar;
	UINT8 unit_id;
	UINT32 unit_len;
    UINT8 line_offset;

	UINT16 wr;

	*len = 0;

	unit_id = *pData++;

	if(Size < 3)
		return RET_NO_DATA;	//not enough data

	unit_len = *pData++;

	if(Size < unit_len+2)
		return RET_NO_DATA;//not enough data


	FieldPolar = (*pData&0x20)>>5;
    line_offset = *pData&0x1F;//cloud

	//pData has 2 bytes offset

//	if(TRUE == vbi_queue_is_full())
//	{
//		return RET_QUEUE_FULL;
//	}
//	else
//	{
		if((TRUE == g_vbi27_pconfig_par->cc_by_vbi) || (TRUE == g_vbi27_pconfig_par->ttx_by_vbi))
		{
			//if(unit_id != 0xff && unit_len <= 44 && enable_vbi == TRUE)//cloud
			if((vbi_queue_is_full()!=TRUE) && ((unit_id == 0x02||unit_id == 0x03) && unit_len <= 44) && (enable_vbi == TRUE))
			{
				wr = vbi_queue_wr_ptr();

				MEMCPY(vbi_data_array[wr].vbi_data,pData,unit_len);
				vbi_data_array[wr].vbi_field = FieldPolar;
				vbi_data_array[wr].unit_id = unit_id;
				vbi_data_array[wr].unit_len = unit_len;

				vbi_queue_put();
			}
		}
		
		if(TRUE == (*g_vbi27_ttx_by_osd))
		{
			if((unit_id == 0x02||unit_id == 0x03) && unit_len==44)
			{
				parse_ttx_data(pData+2) ; // unit_len == 44
			}
		}
		
//	}

	*len = (unit_len+2);
	return RET_OK;//find OK

}
static void clear_ttx_data()
{
	UINT32 i,j;

	for(j=0;j<TTX_BUF_DEPTH;j++)
	{
		for(i=0;i<45;i++)
			vbi_output_proc(j+TTX_START_LINE, i, 0x00);
	}

}

static BOOL send_line_data(UINT8 line_id,UINT8 *pData, UINT8 unit_id,UINT8 unit_len)
{//FieldPolar 1: TOP (7-22), 0 : BOT (320-335)
	UINT32 i;
	UINT8 mychar,field_polar,line_offset,frame_code;
	UINT16 myword;
	UINT16 ByteAddr=0,LineAddr;
	if(unit_len != 0)
	{
		field_polar = ((*pData)&0x20)>>5;
        line_offset = *pData&0x1F;//cloud
        frame_code = *(pData+1);

		LineAddr = line_id;//line_id+6;
        pData++;
		if(unit_id == 0x02 || unit_id == 0x03)
		{
			if(TRUE == g_vbi27_pconfig_par->ttx_by_vbi)
			{
				if(unit_len>1)
				{
					pData++;//frame_code
					vbi_output_proc(LineAddr,ByteAddr++, 0xAA);//clock
					vbi_output_proc(LineAddr,ByteAddr++, 0xAA);
					//vbi_output_proc(LineAddr,ByteAddr++, 0xE4);//frame code
					vbi_output_proc(LineAddr,ByteAddr++, frame_code);//frame code
					for(i=0;i<(UINT32)(unit_len-2);i++)
						vbi_output_proc(LineAddr,ByteAddr++, *pData++);
				}
			}
            return TRUE;
		}
		else if(unit_id == 0xC3)//VPS
		{
			if(TRUE == g_vbi27_pconfig_par->vps_by_vbi)
			{
				//VBI_PRINTF("0xc3\n");
				pData+=(unit_len-1);
			}
		}
		else if(unit_id == 0xC4)//WSS
		{
			if(TRUE == g_vbi27_pconfig_par->wss_by_vbi)
			{
				//VBI_PRINTF("0xc4\n");
				if(unit_len>2)
				{
					mychar = *pData++; //first byte
					myword = mychar+(*pData++<<8);
					tve_write_wss(myword);
				}
				else
				{
					pData++;
				}
			}
		}
		else if(unit_id == 0xC5)//CC
		{
			if(TRUE == g_vbi27_pconfig_par->cc_by_vbi)
			{
				//VBI_PRINTF("0xc5\n");
				if(unit_len>2)
				{
					mychar = *pData++; //first byte
					myword = mychar+(*pData++<<8);
					tve_write_cc(field_polar,myword);
				}
				else
				{
					pData++;
				}
			}
		}
		else if(unit_id == 0xC6)//monochrome
		{
		//VBI_PRINTF("0xc3\n");
			pData+=(unit_len-1);
		}
		else
		{
		//VBI_PRINTF("%x\n",unit_id);
			pData+=(unit_len-1);
		}
	}
    return FALSE;
}
//static UINT8 lang_char[256];
void
lang_init(void)
{

//    ttx_gen_char();
//    int i;
//
//    memset(lang_char, 0, sizeof(lang_char));
//    for (i = 1; i <= 13; i++)
//	lang_char[lang_chars[0][i]] = i;

//    UINT8 i, j;
//
//    for(i = 0; i < MAX_NATION; i++)
//    {
//        for(j = 0; j < 13; j++)
//        {
//            libc_printf(" 0x%2x",lang_chars[1+i][j+1]);
//            dly_tsk(100);
//        }
//        libc_printf("\n");
//    }

//    for(i = 0; i < 6; i++)
//    {
//        for(j = 0; j < 16; j++)
//        {
//            libc_printf(" 0x%2x",g2map_latin1[i*16+j]);
//            dly_tsk(100);
//        }
//        libc_printf("\n");
//    }
//
//    libc_printf("\n");
//
//    for(i = 0; i < 6; i++)
//    {
//        for(j = 0; j < 16; j++)
//        {
//            libc_printf(" 0x%2x",g2map_latin2[i*16+j]);
//            dly_tsk(100);
//        }
//        libc_printf("\n");
//    }
}

static void vbi_m3327_software_init(struct vbi_m3327_private * priv)
{
	INT32 i;

	priv->uNotEnoughDataFlag = 0;

	vbi_sbf_create();
	vbi_hdr_buf_create();
    if(TRUE == (*g_vbi27_ttx_by_osd))
	pbf_create();
	for(i=0;i<VBI_BS_HDR_LEN;i++)
	{
		vbi_data_hdr[i].bInfoValid = FALSE;
		vbi_data_hdr[i].uDataSize = 0;
	}
	priv->InitHdr.uDataSize = 0;
	priv->pVBIWrHdr = &priv->InitHdr;
	priv->pVBIRdHdr = &priv->InitHdr;


	vbi_queue_init();

	if(TRUE == (*g_vbi27_ttx_by_osd))
	{
		if(NULL != priv->init_ttx_decoder)
			priv->init_ttx_decoder();
	}
}

static void parse_vbi_stream(struct vbi_m3327_private * priv)
{
	UINT8 ret;

	UINT32 uHdrPtr;
	UINT32 uSize;
	UINT8 * puData;

	UINT32 len;

	while(1)
	{
		if(priv->pVBIRdHdr->uDataSize == 0)
		{
			if(vbi_hdr_buf_rd_req(&uHdrPtr) == RET_SUCCESS)
			{
				priv->pVBIRdHdr = &vbi_data_hdr[uHdrPtr];
				// to do : judge pts sync
				vbi_hdr_buf_rd_update();
			}
			else
			{
				//soc_printf("Exit1\n");
				goto ERR_POINT;//return RET_FAILURE;
			}
		}
		if(priv->uNotEnoughDataFlag ==1)
		{
			if(priv->pVBIRdHdr->uPesStart == 1)
			{
				vbi_sbf_rd_update(priv->uRemainDataSize);
				VBI_PRINTF("5. rd upd \n");
			}
			else if(priv->puRemainDataPtr > priv->pVBIRdHdr->puStartPoint)
			{
				VBI_ASSERT(priv->uRemainDataSize<=LOOPBACK_SIZE);
				//vbi_sbf_rd_update(priv->uRemainDataSize);
				//VBI_PRINTF("4. rd upd = %d \n",priv->uRemainDataSize);

				vbi_sbf_loopback(priv->puRemainDataPtr,priv->uRemainDataSize,priv->pVBIRdHdr->puStartPoint);
				priv->pVBIRdHdr->uDataSize += priv->uRemainDataSize;
				priv->pVBIRdHdr->puStartPoint -= priv->uRemainDataSize;

			}
			else
			{
				priv->pVBIRdHdr->uDataSize += priv->uRemainDataSize;
				priv->pVBIRdHdr->puStartPoint = priv->puRemainDataPtr;
			}
			priv->uNotEnoughDataFlag = 0;
		}
		uSize = priv->pVBIRdHdr->uDataSize;
		if(vbi_sbf_rd_req(&uSize,&puData) != RET_SUCCESS)
		{
			VBI_PRINTF("No Buffer Data\n");
			VBI_ASSERT(FALSE);
			goto ERR_POINT;//return RET_FAILURE;
		}
		else
		{
			VBI_ASSERT(puData== priv->pVBIRdHdr->puStartPoint);

			if(priv->pVBIRdHdr->uPesStart == 1)
			{
				if(*puData != 0x10)
				{
					VBI_PRINTF("this is not a VBI pes!\n");
					vbi_sbf_rd_update(uSize);
					priv->pVBIRdHdr->uDataSize = 0;
					continue;
					//ASSERT(FALSE);//break;
				}
				VBI_PRINTF("1. rd upd = 1 \n");
				vbi_sbf_rd_update(1);

				priv->pVBIRdHdr->uDataSize -= 1;
				priv->pVBIRdHdr->puStartPoint +=1;
				priv->pVBIRdHdr->uPesStart = 0;

				continue;
			}

			while((ret = do_line_data(puData, uSize,&len)) == RET_OK)
			{
				VBI_PRINTF("2. rd upd = %d \n",len);
				vbi_sbf_rd_update(len);
				priv->pVBIRdHdr->uDataSize -= len;
				priv->pVBIRdHdr->puStartPoint += len;

				puData += len;
				uSize -= len;
			}
			if (ret == RET_NO_DATA)//not enough data
			{
				VBI_PRINTF("not enough data\n");
				priv->uRemainDataSize = uSize;
				priv->puRemainDataPtr = puData;
				priv->uNotEnoughDataFlag = 1;
				priv->pVBIRdHdr->uDataSize = 0;
				continue;
			}
			else if(ret == RET_QUEUE_FULL)
			{
				//soc_printf("Exit2\n");
				goto ERR_POINT;
			}

		}
	}
ERR_POINT:

	return;

}

extern OSAL_ID ttx_subt_alarm_id;  // added for ttx_subt clean
void VBIDec_Task(UINT32 param1,UINT32 param2)
{

	OSAL_ER ret;
	OSAL_ER result;
	UINT32 flgptn ;

 	struct vbi_m3327_private * priv = (struct vbi_m3327_private*)(((struct vbi_device*)param1)->priv) ;


	while(1) // run forever when task exist.
	{
		if(priv->status == VBI_STATE_IDLE)
		{
			result = osal_flag_wait(&flgptn,vbidec_flag_id, VBI_CMD_START, OSAL_TWF_ORW, OSAL_WAIT_FOREVER_TIME);

			if(flgptn&VBI_CMD_START)
			{
				VBI_PRINTF("ttx_start_flag!\n");
				vbi_m3327_software_init(priv);
				osal_flag_clear(vbidec_flag_id, VBI_CMD_STOP|VBI_CMD_START|VBI_MSG_DATA_AVAILABLE);
				priv->status = VBI_STATE_PLAY;
				osal_flag_set(vbidec_flag_id,VBI_MSG_START_OK);
			}
		}
		if(priv->status == VBI_STATE_PLAY)
		{
			result = osal_flag_wait(&flgptn,vbidec_flag_id, VBI_CMD_STOP|VBI_MSG_DATA_AVAILABLE, OSAL_TWF_ORW, 20);
			if(result == E_TIMEOUT)
			{
				parse_vbi_stream(priv);
			}
			else if(flgptn&VBI_CMD_STOP)
			{
				VBI_PRINTF("ttx_stop_flag!\n");
				priv->status = VBI_STATE_IDLE;
				osal_flag_clear(vbidec_flag_id, VBI_CMD_STOP|VBI_CMD_START|VBI_MSG_DATA_AVAILABLE);
                #ifdef SUPPORT_TTX_SUBT_TIMER_CLEAN
                if(ttx_subt_alarm_id != OSAL_INVALID_ID)    // Delete working ttx_subt timer when ttx task need to stop
                {
                    libc_printf("delte timer forec\n");
                    osal_timer_delete(ttx_subt_alarm_id);
                    ttx_subt_alarm_id = OSAL_INVALID_ID;
                }
                #endif
				flgptn = 0;
				osal_flag_set(vbidec_flag_id,VBI_MSG_STOP_OK);			
			}	
			else if(flgptn&VBI_MSG_DATA_AVAILABLE)
			{
				//VBI_PRINTF("update flag received!\n");
				osal_flag_clear(vbidec_flag_id, VBI_MSG_DATA_AVAILABLE);
				parse_vbi_stream(priv);
			}
		}


	}//end main while loop


}
__ATTRIBUTE_REUSE_
INT32 vbi_m3327_open(struct vbi_device *dev)
{
	struct vbi_m3327_private *priv = (struct vbi_m3327_private *)(dev->priv);
	OSAL_T_CTSK t_ctsk;

	vbidec_flag_id=osal_flag_create(0x00000000);
	if(OSAL_INVALID_ID==vbidec_flag_id)
	{
	        VBI_PRINTF("Create flag of ttxdec  failed!\n");
		 VBI_ASSERT(0);
	}

	t_ctsk.task = (FP)VBIDec_Task;
	t_ctsk.para1 = (UINT32)dev;
	t_ctsk.para2 = 0;
	t_ctsk.stksz = 0x0C00;
	t_ctsk.quantum = 10;
       t_ctsk.itskpri = OSAL_PRI_HIGH; //OSAL_PRI_NORMAL; //OSAL_PRI_HIGH;

#ifdef _TDS_INFO_MONITOR
    t_ctsk.name[0] = 'V';
    t_ctsk.name[1] = 'B';
    t_ctsk.name[2] = '0';
#endif
	vbidec_tsk_id = osal_task_create(&t_ctsk);
	if(OSAL_INVALID_ID==vbidec_tsk_id)
	{
	        VBI_PRINTF("Can not create VBIDec_Task!!!\n");
		 VBI_ASSERT(0);
	}

	if(NULL != priv->init_cc_decoder)
	{
		priv->init_cc_decoder(dev);
	}
	
	return RET_SUCCESS;
}

INT32 vbi_m3327_close(struct vbi_device *dev)
{
	if(OSAL_E_OK!=osal_task_delete(vbidec_tsk_id))
	{
		while(1)
		{
		    VBI_PRINTF("Delete ttxdec task of %s failed!\n");
		    osal_task_sleep(2000);
		}
	}

	if(OSAL_E_OK!=osal_flag_delete(vbidec_flag_id))
	{
		while(1)
		{
		    VBI_PRINTF("Delete ttxdec flag of %s failed!\n");
		    osal_task_sleep(2000);
		}
	}
	/* clear vbi data when close*/

	return RET_SUCCESS;
}

INT32  vbi_m3327_start(struct vbi_device *dev,t_TTXDecCBFunc pCBFunc)
{

      struct vbi_m3327_private * priv = (struct vbi_m3327_private*)(dev->priv) ;
      UINT32 flgptn ;
      OSAL_ER result;

	if(priv->status == VBI_STATE_IDLE)
	{
     		//MEMSET(g_ttx_p26_nation, 0xff, 25*40*400);
	      if(TRUE == g_vbi27_pconfig_par->parse_packet26_enable)
		      MEMSET(g_ttx_p26_nation, 0x00, 25*40*400);//cloud

		osal_flag_set(vbidec_flag_id, VBI_CMD_START);
		flgptn = 0;
		result = osal_flag_wait(&flgptn,vbidec_flag_id, VBI_MSG_START_OK, OSAL_TWF_ORW, OSAL_WAIT_FOREVER_TIME);
		if(OSAL_E_OK!=result)
		{
		         VBI_PRINTF("Wait VBI_MSG_START_OK failed with err code %s\n",
		         result == OSAL_E_TIMEOUT?"OSAL_E_TIMEOUT":"OSAL_E_FAIL");
		         return !RET_SUCCESS;
		}
		osal_flag_clear(vbidec_flag_id, VBI_MSG_START_OK);

		if(TRUE == (*g_vbi27_ttx_by_osd))
		{
#ifdef SEE_CPU
            pCBPageUpdate = ttx_eng_update_page_cb;
            g_vbi_device = dev;
#else
			pCBPageUpdate = pCBFunc;
#endif
		}
	}

	return RET_SUCCESS;
}
INT32  vbi_m3327_stop(struct vbi_device *dev)
{
      struct vbi_m3327_private * priv = (struct vbi_m3327_private*)(dev->priv) ;
      UINT32 flgptn ;
      OSAL_ER result;

	if(priv->status == VBI_STATE_PLAY)
	{
		osal_flag_set(vbidec_flag_id, VBI_CMD_STOP);
		flgptn = 0;
		result = osal_flag_wait(&flgptn,vbidec_flag_id, VBI_MSG_STOP_OK, OSAL_TWF_ORW, OSAL_WAIT_FOREVER_TIME);
		if(OSAL_E_OK!=result)
		{
		         VBI_PRINTF("Wait VBI_MSG_START_OK failed with err code %s\n",
		         result == OSAL_E_TIMEOUT?"OSAL_E_TIMEOUT":"OSAL_E_FAIL");
		         return !RET_SUCCESS;
		}
		osal_flag_clear(vbidec_flag_id, VBI_MSG_STOP_OK);

		if(TRUE == *g_vbi27_ttx_by_osd)
			pCBPageUpdate = NULL;
	}
       return RET_SUCCESS;
}
/*
void vbi_register_cb(struct vbi_device *dev,t_VBIDecCBFunc pCBFunc)
{
	pCBPageUpdate = pCBFunc;
}
*/
extern BOOL g_IsHDVideo;
INT32 vbi_m3327_request_write(struct vbi_device *dev,UINT32 uSizeRequested,struct control_block* pTDataCtrlBlk,UINT8** ppuData,UINT32* puSizeGot)
{
	UINT32 uReqSize;
	UINT32 uVBIReqHdrWrPtr;

	static UINT8 last_stcid =0xff;
	static UINT32 last_pts = 0;

	struct vbi_m3327_private * priv = (struct vbi_m3327_private*)(dev->priv) ;
	if(priv->status == VBI_STATE_IDLE)
	{
		VBI_PRINTF("VBI_STATE_IDLE!\n");
		return RET_STA_ERR;
	}

	if(g_IsHDVideo)
	{
		VBI_PRINTF("VBI_HD_ABORD!\n");
		return RET_STA_ERR;
	}

	uSizeRequested= (uSizeRequested>552)?552:(uSizeRequested);

	uReqSize= uSizeRequested;
	//VBI_PRINTF("\nD WR REQ(%x):\n",uSizeRequested);
	if(vbi_sbf_wr_req(&uReqSize, ppuData)==RET_FAILURE)
	{
		VBI_PRINTF("SBF request write FAILURE.");
		return RET_FAILURE;
	}
	//VBI_PRINTF("size= %x ,wpt = %x\n",uReqSize,*ppuData);

	if(vbi_hdr_buf_wr_req(&uVBIReqHdrWrPtr)==RET_FAILURE)
	{
		VBI_PRINTF("HDR request write FAILURE.");
		return RET_FAILURE;
	}
	priv->pVBIWrHdr = &vbi_data_hdr[uVBIReqHdrWrPtr];
	priv->pVBIWrHdr->puStartPoint = *ppuData;
	priv->pVBIWrHdr->uDataSize = 0;

	if (NULL == pTDataCtrlBlk)
		priv->pVBIWrHdr->bInfoValid = FALSE;
	else
	{
		priv->pVBIWrHdr->bInfoValid = TRUE;
		priv->pVBIWrHdr->uPesStart = (pTDataCtrlBlk->data_continue == 0x00)?0x01:0x00;

		if(pTDataCtrlBlk->pts_valid == 1)
		{
			last_stcid = pTDataCtrlBlk->stc_id;
			last_pts = pTDataCtrlBlk->pts;
		}
		priv->pVBIWrHdr->uStcId = last_stcid;
		priv->pVBIWrHdr->uPTS = last_pts;
		pTDataCtrlBlk->instant_update = 1;
	}


	*puSizeGot = (uReqSize>uSizeRequested? uSizeRequested : uReqSize);
	return RET_SUCCESS;

}

void vbi_m3327_update_write(struct vbi_device *dev,UINT32 uDataSize)
{
	//Not more than 1 time update .
	struct vbi_m3327_private * priv = (struct vbi_m3327_private*)(dev->priv) ;
	if(priv->status == VBI_STATE_IDLE)
	{
		VBI_PRINTF("VBI_STATE_IDLE!\n");
		return ;
	}

	if(g_IsHDVideo)
	{
		VBI_PRINTF("VBI_HD_ABORD!\n");
		return;
	}

       if(!uDataSize)return ;
	if(priv->pVBIWrHdr==NULL) return;

	 vbi_sbf_wr_update(uDataSize);

	//VBI_PRINTF("wr upd = %d\n",uDataSize);

	priv->pVBIWrHdr->uDataSize += uDataSize;
	vbi_hdr_buf_wr_update();
	priv->pVBIWrHdr=NULL;

	osal_flag_set(vbidec_flag_id,VBI_MSG_DATA_AVAILABLE);
	return ;
}

//#define ENABLE_ATSC_USER_DATA //disable this to pass compile of S3602F dual CPU FPGA. Later, we need to enable this by support TTX remote call
#ifdef ENABLE_ATSC_USER_DATA

#define USER_DATA_LENGTH_MAX	104//xing for DTVCC
#define USER_DATA_ARRAY_MAX	20//10
extern UINT8 g_user_data[USER_DATA_ARRAY_MAX][USER_DATA_LENGTH_MAX];
extern INT32 g_user_data_array_cnt;
extern INT32 g_user_data_array_rd;

static void atsc_user_data_cc(UINT8 FieldPolar)
{
	UINT8 i,j=0,cc_cnt;
	UINT8 byte1,byte2;
	UINT8 cc_field=0;
	BOOL push_1=FALSE, push_2=FALSE;
	static BOOL XDS=FALSE;
	//if(FieldPolar == 0) return;// current is Top field linemeet ,return

	UINT8 rd_idx;
	//g_vbi_priv->vbi_line21_push_by_cc((((g_user_data[rd_idx][i*3+8])&0X7F)<<8)|(g_user_data[rd_idx][i*3+9])&0X7F);
	//
	if(g_user_data_array_cnt>0)
	{
		rd_idx = g_user_data_array_rd;
		if(g_user_data[rd_idx][0]==0x47			//'G'
			&&g_user_data[rd_idx][1]==0x41		//'A'
			&&g_user_data[rd_idx][2]==0x39		//'9'
			&&g_user_data[rd_idx][3]==0x34		//'4'
			&&g_user_data[rd_idx][4]==0x03		//cc indicator
			&&(g_user_data[rd_idx][5]&0x40)==0x40		//process_cc_data_flag
		)
		{
			cc_cnt = g_user_data[rd_idx][5]&0x1f;
			/*
			if(*g_vbi27_cc_by_osd != 0)
				cc_cnt = (cc_cnt>2)?2:cc_cnt;// xing 20070522 for DTVCC unused
				*/
			//em_data = g_user_data[6];
			//vbi_CC=FALSE;
			for(i=0;i<cc_cnt;i++)
			{
				if((g_user_data[rd_idx][i*3+7]&0x04) == 0x04)//cc_valid == 1
				{
					byte1=(g_user_data[rd_idx][i*3+8])&0X7F;
					byte2=(g_user_data[rd_idx][i*3+9])&0X7F;
			
					if((byte1==0x01 && byte2==0x05) ||(byte1==0x09 && byte2==0x01) || (byte1==0x09 && byte2==0x02) \
						|| (byte1==0x0a && byte2==0x01) || (byte1==0x0a && byte2==0x02) ) //v-chip , puplic service & puplic service cont.
						XDS=TRUE;
					if((byte1>=0x10&&byte1<=0x1f)&&(!(byte2>0x2f&&byte2<0x40)) && byte2>=0x20&&byte2<=0x7f)//control data
						XDS=FALSE;

					push_1 = (*g_vbi27_cc_by_osd==0x00 || *g_vbi27_cc_by_osd==0x01 || *g_vbi27_cc_by_osd==0x02|| *g_vbi27_cc_by_osd==0x05|| *g_vbi27_cc_by_osd==0x06);
					push_2 = ( XDS ||  *g_vbi27_cc_by_osd==0x00 || *g_vbi27_cc_by_osd==0x03 || *g_vbi27_cc_by_osd==0x04|| *g_vbi27_cc_by_osd==0x07|| *g_vbi27_cc_by_osd==0x08);
						
					if((g_user_data[rd_idx][i*3+7]&0x03) == 0x00)//NTSC_CC_FIELD_1
					{
						cc_field=1;
						if(TRUE == g_vbi27_pconfig_par->cc_by_vbi)
							sub_sdhd_write_cc_data(1,(g_user_data[rd_idx][i*3+9]<<8)|g_user_data[rd_idx][i*3+8]); // 1:top, 0:bot
						//vbi_CC=TRUE;	
						if(g_disable_process_cc==TRUE) 
						{
							//soc_printf("recv_PAC=%d\n",recv_PAC);
							recv_PAC=FALSE;
							//MEMSET(g_user_data[rd_idx],0x00,USER_DATA_LENGTH_MAX);
							//return;
						}	
					
						if(push_1 )//cc1 cc2 tt1 tt2
						{
							if((NULL!=g_vbi_priv->vbi_line21_push_by_cc) && (NULL!=g_vbi_priv->cc_push_field))
							{
								g_vbi_priv->cc_push_field(cc_field);
								g_vbi_priv->vbi_line21_push_by_cc((byte1<<8)|byte2);

						}
					}
//						
						}
					else if((g_user_data[rd_idx][i*3+7]&0x03) == 0x01)//NTSC_CC_FIELD_2
					{
						cc_field=2;
						if(TRUE == g_vbi27_pconfig_par->cc_by_vbi)
							sub_sdhd_write_cc_data(0,(g_user_data[rd_idx][i*3+9]<<8)|g_user_data[rd_idx][i*3+8]); // 1:top, 0:bot
		//vbi_CC=TRUE;
						if(g_disable_process_cc==TRUE) 
						{
							recv_PAC=FALSE;
							//MEMSET(g_user_data[rd_idx],0x00,USER_DATA_LENGTH_MAX);
							//return;
						}
						
						if(push_2 )//cc3 cc4 tt3 tt4
							if((NULL!=g_vbi_priv->vbi_line21_push_by_cc) && (NULL!=g_vbi_priv->cc_push_field))
							{
								g_vbi_priv->cc_push_field(cc_field);
								g_vbi_priv->vbi_line21_push_by_cc((byte1<<8)|byte2);
					}
						}
					else if((((g_user_data[rd_idx][i*3+7]&0x03) == 0x03) || ((g_user_data[rd_idx][i*3+7]&0x03) == 0x02)) && (*g_vbi27_dtvcc_by_osd !=0))  //xing 20070522 for DTVCC Packet Start 
					{ 
						if(NULL != g_vbi_priv->vbi_line21_push_by_dtvcc)
						{
								if((g_user_data[rd_idx][i*3+7]&0x03) == 0x03)
								{
									//soc_printf("\n==================start packet =================\n");
									g_vbi_priv->vbi_line21_push_by_dtvcc((0xff<<8)|0xff );
								}	

								// soc_printf("s => ,%x,%x\n",g_user_data[rd_idx][i*3+8],g_user_data[rd_idx][i*3+9] );

								g_vbi_priv->vbi_line21_push_by_dtvcc((((g_user_data[rd_idx][i*3+8])&0XFF)<<8)|(g_user_data[rd_idx][i*3+9])&0XFF);
							}
						}
					if(byte1==0x0f) XDS = FALSE;
				}
			}
		}
		g_user_data_array_cnt--;
		g_user_data_array_rd = (g_user_data_array_rd==USER_DATA_ARRAY_MAX-1)?0:g_user_data_array_rd+1;
	}
	//
}
#endif

static void FeedDataHsr(UINT8 FieldPolar)
{//FieldPolar 1: TOP (7-22), 0 : BOT (320-335)
	UINT16 rd;
	UINT8 i,drop = 0;
	UINT8 send_line_cnt=0;
	UINT8 field = FieldPolar&1;
	UINT8 ntsc = FieldPolar>>4;
	UINT8 max_line_num,line_offset;
    BOOL ttxflag = FALSE;
    UINT8 count_data=0;
    UINT8 real_field;//get from line data
    UINT8 line_data_exsit[16];

	if(FieldPolar==0xFF)
	{
		while(TRUE != vbi_queue_is_empty())
			vbi_queue_get();
		return;
	}

    for(i=0;i<16;i++)
      line_data_exsit[i]=0;
	if(field == 0 && ntsc == 0)
		max_line_num = 16;
	else if(field == 1 && ntsc == 0)
		max_line_num = 16;// we transfer vbi data in line7~22,line320~335
	else if(field == 0 && ntsc == 1)
		max_line_num = 13;
	else// if(field == 1 && ntsc == 1)
		max_line_num = 13;

	if(vbi_queue_cnt<16)
    {
        //libc_printf("not enough data in FeedDataHsr\n");
        return;
    }

    rd = vbi_queue_rd_ptr();
    real_field = (*(vbi_data_array[rd].vbi_data)&0x20)>>5;//cloud
    if(real_field!=field)
    {
        //libc_printf("field not match,wait next field\n" );
        return;
    }    

    if(field==1)
        tve_set_vbi_startline(TTX_START_LINE-1);//line7
    else
        tve_set_vbi_startline(TTX_START_LINE+1-1);//line319->320
    
	if(TRUE == g_vbi27_pconfig_par->ttx_by_vbi)
		clear_ttx_data();

	if((TRUE == g_vbi27_pconfig_par->ttx_by_vbi) || (TRUE == g_vbi27_pconfig_par->cc_by_vbi))
	{
		while(1)
		{
			if(TRUE == vbi_queue_is_empty())
				return;

            if(send_line_cnt>=16 && vbi_queue_cnt<=550)
                return;
            
			rd = vbi_queue_rd_ptr();
			//if(vbi_data_array[rd].vbi_field == FieldPolar)
			if(send_line_cnt<max_line_num)//0~15
			{
                line_offset = *(vbi_data_array[rd].vbi_data)&0x1F;//cloud
                real_field = (*(vbi_data_array[rd].vbi_data)&0x20)>>5;//cloud

                if(real_field!=field)
                {
                      //libc_printf("field not match,wait next field\n" );
                      return;
                }

                if(line_offset<7 || line_offset>22)
                {
                    ///libc_printf("line_offset out of range!\n");
                    vbi_queue_get();
                    continue;
                }
                    
                if(line_data_exsit[line_offset-7]==1)
                {
                    //libc_printf("data exsit,wait !!\n");
                    return;
                }
				//ttxflag = send_line_data(send_line_cnt,vbi_data_array[rd].vbi_data,vbi_data_array[rd].unit_id,vbi_data_array[rd].unit_len);
                ttxflag = send_line_data(line_offset,vbi_data_array[rd].vbi_data,vbi_data_array[rd].unit_id,vbi_data_array[rd].unit_len);
                		vbi_queue_get();
                //if(ttxflag == TRUE)//cloud
				//    send_line_cnt ++;
				send_line_cnt=line_offset-7+1;
                line_data_exsit[line_offset-7] = 1;
                //libc_printf("field=%d,real_field=%d,line_offset=%d,send_line_cnt=%d,rd=%d,vbi_queue_cnt=%d\n",field,real_field,line_offset,send_line_cnt,rd,vbi_queue_cnt);
			}
			else
			{
				if(vbi_queue_cnt>550)
				{
					VBI_PRINTF("D\n");
					drop = 1;
				}
				break;
			}
		}
		if(drop == 1)
		{
			while(TRUE != vbi_queue_is_empty())
				vbi_queue_get();
		}
	}

	return;

}
void RequestVBIData(UINT8 FieldPolar)
{
#ifdef ENABLE_ATSC_USER_DATA    
	if(TRUE == g_vbi27_pconfig_par->cc_by_vbi)
		atsc_user_data_cc(FieldPolar);
#endif    

	if((TRUE == g_vbi27_pconfig_par->ttx_by_vbi) || (TRUE == g_vbi27_pconfig_par->cc_by_vbi))
	{
		if(g_vbi_priv->status == VBI_STATE_PLAY)
    			//osal_interrupt_register_hsr((OSAL_T_HSR_PROC_FUNC_PTR)FeedDataHsr, (DWORD)(FieldPolar));
    			FeedDataHsr(FieldPolar);
	}
}

void vbi_m3327_setoutput(struct vbi_device *dev,T_VBIRequest *pVBIRequest)
{
	*pVBIRequest = RequestVBIData;
}

RET_CODE vbi_m3327_ioctl(struct vbi_device *dev,UINT32 cmd,UINT32 param)
{
    RET_CODE result=RET_SUCCESS ;
    struct vbi_m3327_private *priv = (struct vbi_m3327_private *)(dev->priv);
    switch(cmd)
    {
    case IO_VBI_WORK_MODE_SEPERATE_TTX_SUBT:
        ttx_eng_set_seperate_ttxsubt_mode(dev, param);
        break;
    case IO_VBI_WORK_MODE_HISTORY :
        ttx_eng_set_ttx_history_mode(dev, param);
        break;
    case IO_VBI_ENGINE_OPEN:
        ttx_eng_open(dev, (param>>16)&0xff, param&0xffff);
        break;
    case IO_VBI_ENGINE_CLOSE:
        ttx_eng_close(dev);
        break;
    case IO_VBI_ENGINE_UPDATE_PAGE:
        ttx_eng_update_page(dev, (param>>8)&0xffff, param&0xff);
        break;
    case IO_VBI_ENGINE_SHOW_ON_OFF:
        ttx_eng_show_onoff(dev, param);
        break;
    case IO_VBI_ENGINE_SEND_KEY:
        ttx_eng_send_key(dev, param);
        break;
    case IO_VBI_ENGINE_GET_STATE:
        *(UINT8 *)(param) = ttx_eng_get_state(dev);
        break;
    case IO_VBI_ENGINE_UPDATE_INIT_PAGE:
        {
            struct ttx_page_info *ttx_page_update = (struct ttx_page_info *)(param);
            ttx_eng_update_init_page(dev, ttx_page_update->num, ttx_page_update->page_addr);
        }
        break;
    case IO_VBI_ENGINE_UPDATE_SUBT_PAGE:
        {
            struct ttx_page_info *ttx_page_update = (struct ttx_page_info *)(param);
            ttx_eng_update_subt_page(dev, ttx_page_update->num, ttx_page_update->page_addr);
        }
        break;
    case IO_VBI_ENGINE_SET_CUR_LANGUAGE:
        ttx_eng_set_cur_language(param);
		break;
	case IO_TTX_USER_DSG_FONT:
		ttx_eng_set_ttx_dsg_font(param);
		break;
    case IO_VBI_SELECT_OUTPUT_DEVICE:
        if (g_vbi_priv)
            g_vbi_priv->tve_dev_id = param & 1;
        break;
    default:
        result=!RET_SUCCESS ;
        break ;
    }
    return result;
}


